package com.xh.bussiness.resource.util;

import com.xh.bussiness.resource.bean.dto.VideoFileDto;
import com.xh.core.util.ExecUtils;
import com.xh.core.util.RegexUtils;
import com.xh.core.util.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;

/*
 * @Author daiwei
 * @Description
 * @Date 2020/2/22 00:26
 **/
@Component
public class FfmpegUtils {

    private static String targetUrl;

    @Value("${xh.ffmpeg.target}")
    public void setTargetUrl(String target) {
        FfmpegUtils.targetUrl = target;
    }

    public static String convert(String oriFilePath){
        try {
            VideoFileDto dto = FfmpegUtils.getVideoFileInfo(oriFilePath);
            Long maxRate = null;

            String vcode = null;
            String acode = null;
            Long bitrate = null;
            Long resolutionX = null;
            Long resolutionY = null;
            if (dto != null) {
                if (dto.getVideoEncoder().indexOf("h264") < 0) {
                    vcode = "libx264";
                }
                if (!StringUtils.isEmpty(dto.getAudioEncoder()) && dto.getAudioEncoder().indexOf("aac") < 0) {
                    acode = "aac";
                }
                if (!StringUtils.isEmpty(dto.getResolution()) && dto.getResolution().indexOf("x") >= 0) {
                    try {
                        String[] resolutions = dto.getResolution().split("x");
                        Long x = Long.valueOf(resolutions[0]);
                        Long y = Long.valueOf(resolutions[1]);
                        Long max = 0L;
                        if (x > y) {
                            max = x;
                        } else {
                            max = y;
                        }
                        if (max > 1920L) {
                            if (x > y) {
                                resolutionX = 1920L;
                            } else {
                                resolutionY = 1920L;
                            }
                        }
                        if (max >= 1920L) {
                            maxRate = 4500L;
                        } else if (max >= 1280L) {
                            maxRate = 3000L;
                        } else {
                            maxRate = 2000L;
                        }
                        if (dto.getBitrateKb() > maxRate) {
                            bitrate = maxRate;
                        }
                    } catch (Exception ex) {

                    }
                }
            } else {
                return null;
            }
            return convert(vcode, acode, bitrate, resolutionX, resolutionY, oriFilePath);
        }catch (Exception ex){
            return null;
        }
    }

    /**
     * 将视频文件根据需要转码
     * @param vcode
     * @param acode
     * @param bitrate
     * @param resolutionX
     * @param resolutionY
     * @param oriFilePath
     * @return
     */
    public static String convert(String vcode,String acode,Long bitrate,Long resolutionX,Long resolutionY, String oriFilePath){
        if(vcode==null&&acode==null&&bitrate==null&&resolutionX==null&&resolutionY==null){
            return oriFilePath;
        }
        List<String> cmd=new ArrayList<>();
        String msg=null;
        //ffmpeg -i 1.mp4 -vcodec libx264 -acodec aac -strict -2  -y 11.mp4
        cmd.add(targetUrl + "ffmpeg");
        cmd.add("-i");
        cmd.add(oriFilePath);
        if(vcode!=null) {
            cmd.add("-vcodec");
            cmd.add(vcode == null ? "copy" : "libx264");
        }
        if(acode!=null) {
            cmd.add("-acodec");
            cmd.add(acode == null ? "copy" : "aac");
        }
        cmd.add("-strict");
        cmd.add("-2");
        //-b:v 2000k -bufsize 2000k -maxrate 2500k
        if(bitrate!=null){
            cmd.add("-b:v");
            cmd.add(bitrate+"k");
            cmd.add("-bufsize");
            cmd.add(bitrate+"k");
            cmd.add("-maxrate");
            cmd.add((long)(bitrate*2)+"k");
        }
        if(resolutionX!=null){
            cmd.add("-vf");
            cmd.add("scale="+resolutionX+":-1");
        }
        if(resolutionY!=null){
            cmd.add("-vf");
            cmd.add("scale=-1:"+resolutionY);
        }
        cmd.add("-y");
        cmd.add(oriFilePath + ".mp4");
        System.out.println("cmd:"+ StringUtils.joinList(cmd," "));
        msg = ExecUtils.exec(cmd);
        File file = new File(oriFilePath + ".mp4");
        if (msg.equals("execOpError") || file.length() == 0) {
            return null;
        }
        cmd.clear();
        return oriFilePath + ".mp4";
    }

    /**
     * 获取视频截图
     * @param filepath 文件地址
     * @param count 不填截取一张，张数超过视频秒数，最多返回秒数
     * @param outputPath 输出路径，最后不包含分隔符
     * @return
     */
    public static List<String> screenshotByCount(String filepath,Integer count,String outputPath){
        List<String> result=new ArrayList<>();

        if(count==null||count<=0){
            String coverFile=screenshot(filepath,null,outputPath,"cover_logo");
            if(coverFile!=null){
                result.add(coverFile);
            }
            return result;
        }
        VideoFileDto dto= FfmpegUtils.getVideoFileInfo(filepath);
        if(!StringUtils.isEmpty(dto.getTotalTime())){
            String[] totalTimes=dto.getTotalTime().split("\\.")[0].split(":");
            if(totalTimes==null||totalTimes.length!=3){
                return null;
            }
            Long totalSecond=Long.valueOf(totalTimes[0])*3600+Long.valueOf(totalTimes[1])*60+Long.valueOf(totalTimes[2]);
            Long secondSplit=totalSecond/count;
            for(int i=0;i<count;i++){
                Long second=secondSplit*i;
                Long hour=second/3600;
                Long min=(second%3600)/60;
                Long sec=(second%3600)%60;
                String timeCurr=String.format("%s:%s:%s",(hour<10?("0"+hour):hour),(min<10?("0"+min):min),(sec<10?("0"+sec):sec));
                String coverFile=screenshot(filepath,timeCurr,outputPath,String.format("cover_logo_%d",(i+1)));
                if(coverFile!=null){
                    result.add(coverFile);
                }
            }
        }
        return result;
    }

    public static String getHalfTime(String time){
        String result=null;
        if(!StringUtils.isEmpty(time)){
            String[] totalTimes=time.split("\\.")[0].split(":");
            if(totalTimes==null||totalTimes.length!=3){
                return null;
            }
            Long totalSecond=Long.valueOf(totalTimes[0])*3600+Long.valueOf(totalTimes[1])*60+Long.valueOf(totalTimes[2]);
            Long second=totalSecond/2;
            Long hour=second/3600;
            Long min=(second%3600)/60;
            Long sec=(second%3600)%60;
            result=String.format("%s:%s:%s",(hour<10?("0"+hour):hour),(min<10?("0"+min):min),(sec<10?("0"+sec):sec));
        }
        return result;
    }

    /**
     * 截图
     * @param filepath 文件地址
     * @param time 时间点 HH:mm:ss,默认00:00:00
     * @param outputPath 输出路径，最后不包含分隔符
     * @param filenamePre 输出文件名前缀
     * @return
     */
    public static String screenshot(String filepath,String time,String outputPath,String filenamePre){
        if(StringUtils.isEmpty(time)){
            time="00:00:00";
        }
        File outputDir=new File(outputPath);
        if(!outputDir.exists()){
            outputDir.mkdirs();
        }
        List<String> cmd=new ArrayList<>();
        String msg=null;
        cmd.add(targetUrl + "ffmpeg");
        cmd.add("-ss");
        cmd.add(time);
        cmd.add("-i");
        cmd.add(filepath);
        cmd.add("-t");
        cmd.add("1");
        cmd.add("-y");
        cmd.add("-r");
        cmd.add("1");
        cmd.add("-q:v");
        cmd.add("2");
        cmd.add("-frames:v");
        cmd.add("1");
        cmd.add("-f");
        cmd.add("image2");
        cmd.add(outputPath+"/"+filenamePre+".png");

        cmd.forEach(item -> System.out.println(item));

        msg=ExecUtils.exec(cmd);
        return outputPath+"/"+filenamePre+".png";
    }

    /**
     * 视频文件切片
     * @param filepath 文件地址
     * @param outputPath 输出路径，最后不包含分隔符
     * @param filenamePre 输出文件名前缀
     * @return
     */
    public static String slice(String filepath,String outputPath,String filenamePre){
        File outputDir=new File(outputPath);
        if(!outputDir.exists()){
            outputDir.mkdirs();
        }
        List<String> cmd=new ArrayList<>();
        String msg=null;
        cmd.add(targetUrl + "ffmpeg");
//        cmd.add("-re");
        cmd.add("-i");
        cmd.add(filepath);
        cmd.add("-c:v:1");
//        cmd.add("-codec");
        cmd.add("copy");
        cmd.add("-c:a:1");
//        cmd.add("-codec");
        cmd.add("copy");
        cmd.add("-strict");
        cmd.add("-2");
        cmd.add("-y");
        cmd.add("-bsf:v");
        cmd.add("h264_mp4toannexb");
        cmd.add("-f");
        cmd.add("hls");
        cmd.add("-hls_list_size");
        cmd.add("0");
//        cmd.add("4");
//        cmd.add("-hls_wrap");
//        cmd.add("20");
        cmd.add("-hls_time");
        cmd.add("5");
        cmd.add("-y");
//        cmd.add("-hls_segment_filename");
//        cmd.add(hlsPath+"/video-%d.ts");
        cmd.add(outputPath+"/"+filenamePre+".m3u8");
//                    String convertCmd = "/usr/bin/ffmpeg -re -i " + oriFilePath + " -codec copy -f hls -hls_list_size 4 -hls_wrap 20 -hls_time 5 -hls_segment_filename "+hlsPath+"/video-%d.ts "+hlsPath+"/video.m3u8";
        msg=ExecUtils.exec(cmd);
        //file.delete();
        if(msg.equals("execOpError")||msg.toString().indexOf("Conversion failed")>=0){
            System.out.println(msg.toString());
            return null;
        }
        return outputPath+"/"+filenamePre+".m3u8";
    }
    /**
     * 获取视频基本信息
     * @param filepath
     * @return
     */
    public static VideoFileDto getVideoFileInfo(String filepath){
        VideoFileDto dto=new VideoFileDto();
        List<String> cmd=new ArrayList<>();
        //ffmpeg -i 1.mp4 -vcodec libx264 -acodec aac -strict -2  -y 11.mp4
        cmd.add(targetUrl + "ffmpeg");
        cmd.add("-i");
        cmd.add(filepath);
        String msg= ExecUtils.exec(cmd);
        if (!StringUtils.isEmpty(msg)) {
            try {
                String regexDuration = "Duration: (.*?), start: (.*?), bitrate: (\\d*) kb\\/s";
                String regexVideo = "Video: (.*?), (.*?), (.*?), (.*?)[,\\s]";
                String regexAudio = "Audio: (.*?), (.*?), (.*?), (.*?)[,\\s]";

                Matcher m = RegexUtils.getMatcher(msg, regexDuration);

                if (m.find()) {
                    dto.setTotalTime(m.group(1));
                    try {
                        dto.setBitrateKb(Long.valueOf(m.group(3)));
                    }catch (Exception ex){

                    }
                }

                m = RegexUtils.getMatcher(msg, regexAudio);

                if (m.find()) {
                    dto.setAudioEncoder(m.group(1));
                }

                m = RegexUtils.getMatcher(msg, regexVideo);

                if (m.find()) {
                    String resolution= RegexUtils.Match(m.group(3),"([1-9]\\d*)x([1-9]\\d*)")?m.group(3):m.group(4);
                    resolution=resolution.split(" ")[0];
                    dto.setResolution(resolution);
                    dto.setVideoEncoder(m.group(1));
                }
                return dto;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    public static void main(String[] args) {
//        VideoFileDto dto=FfmpegUtils.getVideoFileInfo("/Users/david/Downloads/本地测试.mp4");
//        VideoFileDto dto=FfmpegUtils.getVideoFileInfo("/Users/david/Downloads/01.引爆摩天楼.rmvb");
//        VideoFileDto dto=FfmpegUtils.getVideoFileInfo("/Users/david/Documents/1.mp4.mp4");
//        System.out.println(dto);
//        System.out.println(getHalfTime("00:21:11.123"));
        //screenshotByCount("/Users/david/Downloads/60秒--改.mp4",20,"/Users/david/Downloads/111");
        String path= FfmpegUtils.convert("/Users/david/Documents/1582882541047611774.mp4");
    }
}
